
/// .Text段存放的是程序中的可执行代码
/// .Data段保存的是已经初始化了的全局变量和静态变量
/// .ROData（ReadOnlyData）段存放程序中的常量值，如字符串常量
/// .BSS段存放的是未初始化的全局变量和静态变量，程序执行前会先进行一遍初始化
#[allow(dead_code)]
const G_ARRY: [i32; 5] = [10; 5];
#[allow(dead_code)]
const G_X: i32 = 100;
#[allow(dead_code)]
static G_VAR: i32 = 1000;
#[test]
fn test06_heap_or_stack() {
    let s: &str = "test list";
    //字符串字面量，位于ROData段
    println!("&str: {:p}", s);//&str: 0x7ff77e4c6b88
    println!("{:p}", &G_ARRY);//data段:0x7ff6c5fc6bb8
    println!("{:p}", &G_X);//data段:0x7ff6c5fc64f0
    println!("{:p}", &G_VAR);//data段:0x7ff77e4c6200
    println!("{}", "-".repeat(10));

    // 位于堆
    let bi = Box::new(30);
    println!("{:p}", bi);//堆:0x19f6c6585e0
    // 将字符串字面量从内存中的代码区（ROData段）复制一份到堆
    // 栈上分配的变量s1指向堆内存
    let s1: String = String::from("Hello");
    // 可以通过std::mem::transmute将
    // 从24字节的长度的3个uszie读出来
    let pstr: [usize; 3] = unsafe { std::mem::transmute(s1) };
    // pstr[0]是一个堆内存地址
    println!("ptr: 0x{:x}", pstr[0]);//ptr: 0x19f6c658750

    println!("{}", "-".repeat(10));
    // 位于栈
    let nums1 = [1, 2, 3, 4, 5, 6];
    let list: Vec<i32> = vec![20,30,40];
    let t = 100;
    println!("{:p}", &t);//栈0x116aeff104
    println!("{:p}", &nums1);//栈0x116aeff0d0
    println!("{:p}", &list);//栈0x116aeff0e8
    // 从ROData区复制了一份字符串放到堆上，
    let s: String = "Hello".to_owned();
    println!("{:p}", &s);//0x116aeff1f8
    let s: String = String::from("Hello");
    println!("{:p}", &s);//0x116aeff260
    let s: String = "Hello".into();
    println!("{:p}", &s);//0x116aeff2c8
}

#[test]
#[allow(dead_code)]
#[allow(unused_variables)]
fn test07_lifecycle() {
    let x = Box::new(100i32);

    // 下面代码报错，返回值缺少具名生命周期参数
    // fn max1(x: &i32, y: &i32) -> &i32 {
    //     if x>y {x} else {y}
    // }
    fn max2<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
        if x>y {x} else {y}
    }

    println!("{}", max2(&13,&19));

    
    let mys = std::sync::Arc::new(String::from("xxxx"));
    let mys1 = mys.clone();
    std::thread::spawn(move || { 
        println!("{}", mys1);
    });
    println!("{}", mys);
    

    // 错误：需要标注返回类类型的生命周期
    fn lifetime1() -> &'static str { 
        let name = "Hello"; 
        &name[1..]
    }
    fn lifetime11() -> String {
        let name = "Tyr".to_string();
        name[1..].to_string()
    }

    // // 错误，为什么？
    fn lifetime2(name: &String) -> &str { 
        &name[1..]
    }

    use std::str::Chars;
    // // 正确，为什么？
    fn lifetime3<'a>(name: &'a str) -> Chars<'a> { 
        name.chars()
    }

    let t = std::rc::Rc::new(1);
    let op = Some("aaa");

}

/// rust的函数类型和闭包
/// rust是一门函数式编程语言，函数是一等公民
/// 函数本身可以作为参数进行传递，也可用作返回值
/// 函数参数和返回值必须标明类型
#[test]
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn test08_fn() {
    fn add(x: i32, y: i32) -> i32 {
        x + y
    }
    fn sub(x: i32, y: i32) -> i32 {
        x - y
    }
    // 函数可以被作为变量对待
    let var_add: fn(i32, i32)->i32 = add;
    let ref_add = &add;
    println!("{}", add(2,3));//5
    println!("{}", var_add(2,3));//5
    println!("{}", ref_add(2,3));//5

    // 函数类型作为参数
    fn binary_op(op: fn(i32,i32)->i32, operand1: i32, operand2: i32) -> i32 {
        op(operand1, operand2)
    }
    // add函数作为binary_op的第一个参数
    println!("{}", binary_op(add, 2, 3));//5

    // 函数类型作为返回值
    fn get_binary_fn(t: u8) -> fn(i32,i32)->i32 {
        match t {
            b'-'=> sub,
            _ => add,
        }
    }
    let f = get_binary_fn(b'-');
    println!("sub: {}", f(100,15));//85


    // 闭包的定义形式：|args|{codes}
    // 如果codes中只有一个表达式，大括号可以省略
    // closure1的类型为：|i32,i32|->i32
    // 如果在闭包前面加move关键字，则捕获的变量所有权将被转移到闭包内
    let closure1 = |x:i32,y:i32|x+y;
    println!("{}", closure1(10,20)); //30

    //闭包作为函数参数
    fn call_closure(arg: i32, c: impl Fn(i32)->i32) {
        println!("call_closure, ans={}", c(arg));
    }
    call_closure(30, |x|x*x);


    //FnOnce闭包只能被外部调用一次
    let name = String::from("rust");
    // 这个闭包啥也不干，只是把输入greeting和捕获的参数name返回出去
    let c = move |greeting: String| (greeting, name);
    let result = c("hello~".to_string());
    println!("result: {:?}", result);
    // 无法再次调用
    // let result = c("hi~".to_string());

    //FnMut闭包
    let mut name = String::from("hello"); 
    // 捕获 &mut name，
    let mut c_mut = || { 
        name.push_str(" rust"); 
        println!("c: {}", name); 
    }; 
    c_mut();// c: hello rust
    

    let square: &dyn Fn(i32)->i32 = &|x|x*x;
    println!("{}", square(3));

    fn get_panic(x:i32) -> ! {
        panic!("getPanic(): {}", "~~~");
    }
    // get_panic(100);


    let nums = vec![3,2,1,5];
    // 对nums列表中的元素求和
    // iter()取得的是原数据结构中元素的引用
    // fold第二个参数是一个闭包类型
    let sum = nums.iter().fold(0, |acc, n|{
        println!("acc={}, n={}", acc, n);
        acc+n
    });
    println!("orSum is: {}", sum);

    
}

#[test]
#[allow(unused_must_use)]
fn test09_string() {
    // String内部其实是一个Vec<u8>，String类型占用3个usize的内存
    // 可以追加内容，有点像Java中的StringBuilder
    println!("size: {}", std::mem::size_of::<Vec<u8>>());//24
    println!("size: {}", std::mem::size_of::<String>());//24
    // 将字符串字面量从内存中的代码区（ROData段）复制一份到堆
    // String类型s1指向堆内存
    let mut s1: String = String::from("Hello ");
    // 可以通过push_str追加内容
    s1.push_str("Rust!");
    s1.push('!');
    s1.write_char('!');


    println!("{}", "-".repeat(10));
    println!("size: {}", std::mem::size_of::<Vec<u8>>());//24
    println!("size: {}", std::mem::size_of::<String>());//24
    let s: String = String::from("Hello");
    let pstr: [usize; 3] = unsafe { std::mem::transmute(s) };
    //ptr: 0x1c685458950, cap: 5, len: 5
    println!("ptr: 0x{:x}, cap: {}, len: {}", pstr[0], pstr[1], pstr[2]);
    println!("{}", "-".repeat(10));


    let st = "Hello Rust";

    let mut ss = String::with_capacity(256);
    ss.insert(0, 'f');
    ss.insert(1, 'o');
    ss.insert(2, 'o');
    assert_eq!("foo", ss);
    ss.remove(0);
    ss.insert(0, 't');
    assert_eq!("too", ss);
    ss.clear();
    assert_eq!("", ss);

    let s = "Hello Rust".to_owned();

    // 
    // 可以通过std::mem::transmute将
    // 从24字节的长度的3个uszie读出来
    let pstr: [usize; 3] = unsafe { std::mem::transmute(s1) };
    // pstr[0]是一个堆内存地址
    // ptr: 0x273cf37b5f0, cap: 12, len: 12
    println!("ptr: 0x{:x}, cap: {}, len: {}", pstr[0], pstr[1], pstr[2]);

    
    let mut s1: String = String::from("Hello ");
    // 可以通过push_str追加内容
    s1.push_str("Rust!");
    s1.push('!');
    use std::fmt::Write;
    s1.write_char('!');
    s1 += " Hello Rust!";
    println!("{}", s1);

    // Chars是一个u8类型的迭代器，
    // 遍历String中的u8字符
    use std::str::Chars;
    let chs: Chars = s1.chars();
    for ch in chs {
        println!("{}", ch);
    }
    let byts: &[u8] = s1.as_bytes();
    for b in byts {
        println!("{}", b);
    }

    // remove和insert都是O(n)复杂度的
    // remove会导致删除位置后面的所有字符整体前移1个位置
    // insert会导致插入位置后面的所有字符整体后移1个位置
    let mut s1:String = String::from("Hello");
    s1.remove(0);
    s1.insert(0, 'X');
    assert_eq!("Xello", s1);


    // 如何高效修改String中的一个字符
    let mut s1:String = String::from("Hello");
    unsafe {
        let s1_bytes: &mut [u8] = s1.as_bytes_mut();
        s1_bytes[0] = 'X' as u8;
        s1_bytes[1] = 'Y' as u8;
        println!("s1 new={}", s1);
    }
    // String类型转为可修改切片
    let x = s1.as_mut();
    // let x = x.as_mut_ptr();
    // x.bytes().nth(0) = 'X';

    
    trait SetByIndex {
        fn set_by_index(&mut self, idx: usize, c: u8);
    }
    impl SetByIndex for String {
        fn set_by_index(&mut self, idx: usize, c: u8) {
            if idx>=self.len() {
                panic!("Index out of bounds: {}, expected: [0,{})", idx, self.len());
            }
            unsafe {
                let _buf: &mut [u8] = self.as_bytes_mut();
                _buf[idx] = c;
            }
        }
    }
    let mut ss = "Hello".to_owned();
    ss.set_by_index(0, 'X' as u8);
    println!("ss={}", ss);//ss=Xello
    


    let s1: String = "Hello Rust!".to_owned();
    let s2: String = String::from("Hello Rust!");
    let s3: String = "Hello Rust!".to_string();
    assert_eq!(s1,s2);
    assert_eq!(s2,s3);
    assert_eq!(s1,s3);
    println!("s1: {:p}", &s1);//s1: 0x32a62fec08
    println!("s2: {:p}", &s2);//s2: 0x32a62fec20
    println!("s3: {:p}", &s3);//s3: 0x32a62fec38

    let raw1: [usize; 3] = unsafe { std::mem::transmute(s1) };
    // raw1[0]是一个堆内存地址
    // ptr: 0x2749d72c2d0, cap: 11, len: 11
    println!("ptr: 0x{:x}, cap: {}, len: {}", raw1[0], raw1[1], raw1[2]);
    let raw2: [usize; 3] = unsafe { std::mem::transmute(s2) };
    // ptr: 0x2749d72c190, cap: 11, len: 11
    println!("ptr: 0x{:x}, cap: {}, len: {}", raw2[0], raw2[1], raw2[2]);		
    // ptr: 0x2749d72c1d0, cap: 11, len: 11
    let raw3: [usize; 3] = unsafe { std::mem::transmute(s3) };
    println!("ptr: 0x{:x}, cap: {}, len: {}", raw3[0], raw3[1], raw3[2]);		


    // &String类型
    let s1: String = "Hello Rust!".to_owned();
    let s2 = &s1;
    // &str类型，即字符串切片类型
    let s3 = "Hello Rust!";
    // &str类型的"Hello Rust!"，只是对可执行文件加载到内存后RODATA段字符串常量的引用
    // 可以调用to_owned()将字符串复制一份到堆内存上，返回拥有所有权的String类型
    // 看rust源码可知，String::from()实现上就是调用的to_owned()
    let s4: String = "Hello Rust!".to_owned();
    // to_string()实际调用的是String::from，最终仍是调用的to_owned()；
    let s5 = "Hello Rust!".to_string();
    // 格式化打印出s1-s5的内存地址
    
    println!("{:p}", s2);
    println!("{:p}", s3);
    println!("{:p}", &s4);
    println!("{:p}", &s5);

    let slice1 = &s1[0..5];//对String类型进行切片引用
    let slice2 = &s2[0..5];//对&String类型进行切片引用
    let slice3 = &s3[0..5];//对&str切片类型，进行切片引用
    println!("{}", slice1);
    println!("{}", slice2);
    println!("{}", slice3);
}

#[test]
fn test10_iterator() {
    //构造出<=100且能被3整除的正整数

    let mut list1: Vec<i32> = vec![];
    for i in 1..=100 {
        if i%3 == 0 {
            list1.push(i);
        }
    }
    println!("{:?}", list1);

    // 通过一个filter和collect更方便书写
    let list2: Vec<_> = (1..=100).filter(|i| i%3 == 0).collect();
    assert_eq!(list1, list2);



    // use std::slice::Iter;
    use std::iter::Iterator;
    // use std::ops::Range;

    //迭代器的构造和遍历
    let it = &(0..10).into_iter();
    let it = 0..10;//[0,9]
    let it = 0..=10;//[0,10]
    let it = &[1,2,3,4];

    let it = vec![5; 3].iter();
    let it = (0..10).chain(20..30);
    // for-in循环对迭代器进行遍历
    for i in it {
        print!("{} ", i);
    }


    // 取出迭代器中的元素
    // next()方法取得迭代器中下一个元素
    let mut it = 1..=2;
    assert_eq!(Some(1), it.next());
    assert_eq!(Some(2), it.next());
    assert_eq!(None, it.next());

    //take(k)取前面k个元素
    assert_eq!(vec![1,2,3], (1..10).take(3).collect::<Vec<_>>());

    //nth(k)取得迭代器剩余元素中第k个位置的元素的引用，位置从0开始
    // 然后，迭代器跳转到下一个位置
    let mut it = [1, 2, 3].iter();
    assert_eq!(Some(&1), it.nth(0));
    assert_eq!(Some(&2), it.nth(0));
    assert_eq!(Some(&3), it.nth(0));
    assert_eq!(None, it.nth(0));
    assert_eq!(Some(3), (0..4).nth(3));

    //只取最后一个元素
    assert_eq!((1..4).last(), Some(3));

    //对迭代器进行变换
    //skip(k)跳过k个元素
    assert_eq!(vec![2,3], (0..4).skip(2).collect::<Vec<_>>());
    // step_by(k)，从第一个元素开始，每k个取一个出来
    assert_eq!(vec![0,2,4,6], (0..7).step_by(2).collect::<Vec<_>>());
    //chain()方法对迭代器进行顺序拼接合并
    let it = (0..5).chain(15..20);
    //[0, 1, 2, 3, 4, 15, 16, 17, 18, 19]
    println!("{:?}", it.collect::<Vec<_>>());
    // zip()将2个迭代器合并为一个一对一元组迭代器
    let it = [1,3,5].iter().zip([2,4,6].iter());
    assert_eq!(vec![(&1,&2),(&3,&4),(&5,&6)], it.collect::<Vec<(_,_)>>());
    assert_eq!(vec![(0,'f'),(1,'o'),(2,'o')], (0..).zip("foo".chars()).collect::<Vec<_>>());

    //map()方法，对迭代器中每一个元素进行映射，返回一个新的迭代器
    assert_eq!(vec![0,1,4,9,16], (0..5).map(|x|x*x).collect::<Vec<_>>());
    //filter()
    assert_eq!(vec![0,2,4,6,8,10], (0..=10).filter(|x|x%2==0).collect::<Vec<_>>());

    //对迭代器进行求值
    //最大值
    assert_eq!([1,2,3].iter().max(), Some(&3));
    //最小值
    assert_eq!([1,2,3].iter().min(), Some(&1));
    // count()计算迭代器中元素的个数
    assert_eq!([1,2,3].iter().count(), 3);
    // 求和
    assert_eq!([1,2,3].iter().sum::<i32>(), 6);
    //fold()方法
    assert_eq!(3, (1..3).fold(0, |acc, x|acc+x));
    assert_eq!(6, (1..3).fold(0, |acc, x|acc+2*x));

}